
class Strategy(with_metaclass(MetaStrategy, StrategyBase)):
    '''
    Base class to be subclassed for user defined strategies.
    '''

    def qbuffer(self, savemem=0, replaying=False):
        '''启用内存节省方案。``savemem`` 的可能值：

          0: 不节省内存。每个 lines 对象在内存中保留所有值

          1: 所有 lines 对象节省内存，使用严格的最小值

        当需要绘图时，负值可用：

          -1: 策略级别的指标和观察者不启用内存节省（但在其下声明的任何内容都会启用）

          -2: 与 -1 相同，还激活了任何已将 *plotinfo.plot* 声明为 False（不会绘制）的指标的内存节省
        '''

    def _addwriter(self, writer):
        '''
        与其他 _addxxx 函数不同，此函数接收一个实例，因为 writer 在 cerebro 级别工作，仅传递给策略以简化逻辑
        '''

    def _addindicator(self, indcls, *indargs, **indkwargs):
        indcls(*indargs, **indkwargs)

    def _addanalyzer_slave(self, ancls, *anargs, **ankwargs):
        '''与 _addanalyzer 相似，但用于依赖分析器输出数据的观察者（或其他实体）。这些分析器未由用户添加，与主要分析器分开保存

        返回创建的分析器
        '''

    def start(self):
        '''在回测即将开始之前调用。'''

    def stop(self):
        '''在回测即将停止之前调用'''

    def add_timer(self, when,
                  offset=datetime.timedelta(), repeat=datetime.timedelta(),
                  weekdays=[], weekcarry=False,
                  monthdays=[], monthcarry=True,
                  allow=None,
                  tzdata=None, cheat=False,
                  *args, **kwargs):
        '''
        **注意**: 可以在 ``__init__`` 或 ``start`` 中调用

        安排一个计时器来调用一个指定的回调函数或一个或多个策略的 ``notify_timer``。

        参数:

          - ``when``: 可以是

            - ``datetime.time`` 实例（见下面的 ``tzdata``）
            - ``bt.timer.SESSION_START`` 引用会话开始
            - ``bt.timer.SESSION_END`` 引用会话结束

         - ``offset`` 必须是一个 ``datetime.timedelta`` 实例

           用于偏移值 ``when``。它在与 ``SESSION_START`` 和 ``SESSION_END`` 结合使用时具有有意义的用途，以指示在会话开始后 ``15 分钟`` 调用计时器等。

          - ``repeat`` 必须是一个 ``datetime.timedelta`` 实例

            指示在第一次调用后，进一步调用是否将在相同的会话中以计划的 ``repeat`` 间隔调度

            一旦计时器超过会话结束，它将被重置为 ``when`` 的原始值

          - ``weekdays``: 一个 **排序的** 可迭代对象，其中包含表示计时器实际可以调用的哪些天（iso 代码，星期一为 1，星期日为 7）的整数

            如果未指定，则计时器将在所有天都处于活动状态

          - ``weekcarry``（默认值：``False``）。如果为 ``True`` 并且未看到工作日（例如交易假期），则计时器将在下一天执行（即使在新的一周中）

          - ``monthdays``: 一个 **排序的** 可迭代对象，其中包含表示必须执行计时器的每月哪些天的整数。例如每月的 *15* 日始终

            如果未指定，则计时器将在所有天都处于活动状态

          - ``monthcarry``（默认值：``True``）。如果未看到该天（周末，交易假期），则计时器将在下一个可用日执行。

          - ``allow``（默认值：``None``）。一个回调函数，它接收一个 ``datetime.date`` 实例，并返回 ``True`` 如果日期允许计时器，否则返回 ``False``

          - ``tzdata`` 可以是 ``None``（默认值），``pytz`` 实例或 ``data feed`` 实例。

            ``None``：``when`` 被按面值解释（即使它不是），这意味着即使它不是，它也会被处理为 UTC。

            ``pytz`` 实例：``when`` 将被解释为在时区实例指定的本地时间中指定。

            ``data feed`` 实例：``when`` 将被解释为在数据 feed 实例的 ``tz`` 参数指定的本地时间中指定。

            **注意**：如果 ``when`` 是 ``SESSION_START`` 或 ``SESSION_END``，并且 ``tzdata`` 是 ``None``，则系统中的第一个 *数据 feed*（即 ``self.data0``）将用作查找会话时间的参考。

          - ``cheat``（默认值为 ``False``）如果为 ``True``，则在经纪人有机会评估订单之前将调用计时器。这打开了在会话开始之前基于开盘价发出订单的机会，例如

          - ``*args``：任何额外的参数都将传递给 ``notify_timer``

          - ``**kwargs``：任何额外的 kwargs 都将传递给 ``notify_timer``

        返回值:

          - 创建的计时器

        '''

    def notify_timer(self, timer, when, *args, **kwargs):
        '''接收计时器通知，其中“timer”是由“add_timer”返回的计时器，“when”是调用时间。 “args”和“kwargs”是传递给“add_timer”的任何其他参数

        实际的“when”时间可能会更晚，但系统可能无法在之前调用计时器。此值是计时器值，而不是系统时间。
        '''

    def notify_cashvalue(self, cash, value):
        '''
        接收策略经纪人的当前资金价值，价值状态
        '''

    def notify_fund(self, cash, value, fundvalue, shares):
        '''
        接收当前现金，价值，基金价值和基金份额
        '''

    def notify_order(self, order):
        '''
        每当有变化时接收订单
        '''

    def notify_trade(self, trade):
        '''
        每当有变化时接收交易
        '''

    def notify_store(self, msg, *args, **kwargs):
        '''从存储提供程序接收通知'''


    def notify_data(self, data, status, *args, **kwargs):
        '''从数据接收通知'''


    def getdatanames(self):
        '''
        返回现有数据名称列表
        '''


    def getdatabyname(self, name):
        '''
        使用环境（cerebro）按名称返回给定数据
        '''


    def cancel(self, order):
        '''取消提交给券商的订单'''


    def buy(self, data=None,
            size=None, price=None, plimit=None,
            exectype=None, valid=None, tradeid=0, oco=None,
            trailamount=None, trailpercent=None,
            parent=None, transmit=True,
            **kwargs):
        '''创建一个买入（多头）订单并将其发送到经纪商

          - ``data``（默认值：``None``）

            要为其创建订单的数据。如果为“None”，则使用系统中的第一个数据，“self.datas [0]或self.data0”（又名“self.data”）

          - ``size``（默认值：``None``）

            要使用的大小（正数）数据单位的数量，用于订单。

            如果为“None”，则将通过“getsizer”检索的“sizer”实例用于确定大小。

          - ``price``（默认值：``None``）

            要使用的价格（实时经纪商可能会对实际格式施加限制，如果不符合最小跳动要求，则无效）

            对于“市场”和“收盘”订单，“None”是有效的（市场确定价格）

            对于“限价”、“止损”和“止损限价”订单，此值确定触发点（在“限价”情况下，触发显然是订单应匹配的价格）

          - ``plimit``（默认值：``None``）

            仅适用于“StopLimit”订单。这是设置隐式* Limit *订单的价格，一旦触发* Stop *（使用“price”）后

          - ``trailamount``（默认值：``None``）

            如果订单类型为StopTrail或StopTrailLimit，则这是绝对金额，用于确定距离价格的距离（对于卖出订单为下方，对于买入订单为上方）以保持跟踪停止

          - ``trailpercent``（默认值：``None``）

            如果订单类型为StopTrail或StopTrailLimit，则这是一个百分比金额，用于确定距离价格的距离（对于卖出订单为下方，对于买入订单为上方）以保持跟踪停止（如果也指定了“trailamount”，则将使用它）

          - ``exectype``（默认值：``None``）

            可能的值：

            - ``Order.Market``或``None``。将使用下一个可用价格执行市价订单。在回测中，它将是下一个条的开盘价

            - ``Order.Limit``。只能在给定的“价格”或更高价格下执行的订单

            - ``Order.Stop``。在“价格”处触发并像“Order.Market”订单一样执行的订单

            - ``Order.StopLimit``。在“价格”处触发并作为具有由“pricelimit”给定的价格的隐式* Limit *订单执行的订单

            - ``Order.Close``。只能使用会话的收盘价执行的订单（通常在收盘拍卖期间）

            - ``Order.StopTrail``。在“价格”处触发并保持跟踪停止，距离“trailamount”（或“trailpercent”）（对于卖出订单为下方，对于买入订单为上方），如果价格远离停止，则更新

            - ``Order.StopTrailLimit``。在“价格”处触发并保持跟踪停止，距离“trailamount”（或“trailpercent”）（对于卖出订单为下方，对于买入订单为上方），如果价格远离停止，则更新

          - ``valid``（默认值：``None``）

            可能的值：

              - ``None``：这会生成一个不会过期的订单（也称为* Good till cancel *），并保持在市场上，直到匹配或取消。实际上，经纪人往往会强加时间限制，但这通常很远，时间足以考虑它不会过期

              - ``datetime.datetime``或``datetime.date``实例：将使用该日期生成有效期至给定日期的订单（也称为* good till date *）

              - ``Order.DAY``或``0``或``timedelta（）``：将生成一天有效期至* End of the Session *（也称为* day * order）的订单

              - ``numeric value``：假定这是对``matplotlib``编码的日期时间的值（由``matplotlib``用于绘图）

          - ``tradeid``（默认值：``0``）

            这是由``backtrader``应用的内部值，用于跟踪同一资产上的重叠交易。当通知订单状态更改时，此``tradeid``将发送回*策略*。

          - ``oco``（默认值：``None``）

            另一个``order``实例。此订单将成为OCO（Order Cancel Others）组的一部分。一个订单的执行立即取消同一组中的所有其他订单

          - ``parent``（默认值：``None``）

            控制一组订单的关系，例如由高侧限价卖出和低侧止损卖出括起来的买入。高/低侧订单保持不活动，直到父订单已执行（它们变为活动状态）或已取消/过期（子订单也被取消）括号订单具有相同的大小

          - ``transmit``（默认值：``True``）

            指示订单是否必须**传输**，即：不仅在经纪人中放置，而且还发出。这是为了控制括号订单，其中一个禁用父级和第一组子级的传输，并激活最后一个子级的传输，从而触发所有括号订单的完整放置。

          - ``**kwargs``：其他经纪人实现可能支持额外的参数。 ``backtrader``将*kwargs*传递给创建的订单对象

            示例：如果``backtrader``直接支持的4种订单执行类型不足够，在例如*Interactive Brokers*的情况下，以下内容可以作为*kwargs*传递：

              orderType='LIT'，lmtPrice=10.0，auxPrice=9.8

            这将覆盖``backtrader``创建的设置，并生成具有* touched *价格为9.8和* limit *价格为10.0的``LIMIT IF TOUCHED``订单。

        返回：
          - 提交的订单

        '''


    def sell(self, data=None,
             size=None, price=None, plimit=None,
             exectype=None, valid=None, tradeid=0, oco=None,
             trailamount=None, trailpercent=None,
             parent=None, transmit=True,
             **kwargs):
        '''
        创建卖出（空头）订单并将其发送到经纪人

        有关参数的说明，请参见“buy”的文档

        返回：提交的订单
        '''

    def close(self, data=None, size=None, **kwargs):
        '''
        计数器长/短头寸，关闭它

        有关参数的说明，请参见“buy”的文档

        注意：

          - 如果未提供（默认值：“无”），则从现有位置自动计算“size”（由调用者）

        返回：提交的订单
        '''


    def buy_bracket(self, data=None, size=None, price=None, plimit=None,
                    exectype=bt.Order.Limit, valid=None, tradeid=0,
                    trailamount=None, trailpercent=None, oargs={},
                    stopprice=None, stopexec=bt.Order.Stop, stopargs={},
                    limitprice=None, limitexec=bt.Order.Limit, limitargs={},
                    **kwargs):
        '''
        创建一个括号订单组（低端-买单-高端）。默认行为如下：

          - 发出一个带有执行“限价”的**买入**订单

          - 发出一个*低端*括号**卖出**订单，执行为“停止”

          - 发出一个*高端*括号**卖出**订单，执行为“限价”。

        请参见下面的不同参数

          - ``data``（默认值：``None``）

            要为其创建订单的数据。如果为“None”，则使用系统中的第一个数据，``self.datas[0]或self.data0``（也称为``self.data``）

          - ``size``（默认值：``None``）

            要使用的大小（正数）数据单位的单位用于订单。

            如果为“None”，则使用通过``getsizer``检索的``sizer``实例来确定大小。

            **注意**：相同的大小适用于括号的所有3个订单

          - ``price``（默认值：``None``）

            要使用的价格（实时经纪人可能会对实际格式施加限制，如果不符合最小跳动要求，则无效）

            ``None``对于``Market``和``Close``订单是有效的（市场确定价格）

            对于``Limit``，``Stop``和``StopLimit``订单，此值确定触发点（在``Limit``的情况下，触发显然是应该匹配订单的价格）

          - ``plimit``（默认值：``None``）

            仅适用于``StopLimit``订单。这是设置隐式*限制*订单的价格，一旦触发*停止*（使用``price``）（``price``已使用）

          - ``trailamount``（默认值：``None``）

            如果订单类型为StopTrail或StopTrailLimit，则这是一个绝对金额，用于确定距离价格的距离（对于卖出订单而言，在下面，在买入订单中在上面）保持跟踪停止

          - ``trailpercent``（默认值：``None``）

            如果订单类型为StopTrail或StopTrailLimit，则这是一个百分比金额，用于确定距离价格的距离（对于卖出订单而言，在下面，在买入订单中在上面）保持跟踪停止（如果也指定了``trailamount``，则将使用它）

          - ``exectype``（默认值：``bt.Order.Limit``）

            可能的值：（请参阅方法``buy``的文档

          - ``valid``（默认值：``None``）

            可能的值：（请参阅方法``buy``的文档

          - ``tradeid``（默认值：``0``）

            可能的值：（请参阅方法``buy``的文档

          - ``oargs``（默认值：``{}``）

            传递给主要订单的特定关键字参数（在``dict``中）。默认的``**kwargs``参数将在此之上应用。

          - ``**kwargs``：其他经纪人实现可能支持额外的参数。``backtrader``将把*kwargs*传递给创建的订单对象

            可能的值：（请参阅方法``buy``的文档

            **注意**：此``kwargs``将应用于一个bracket的3个订单。请参阅下面的低端和高端订单的特定关键字参数

          - ``stopprice``（默认值：``None``）

            *低端*停止订单的特定价格

          - ``stopexec``（默认值：``bt.Order.Stop``）

            *低端*订单的特定执行类型

          - ``stopargs``（默认值：``{}``）

            传递给低端订单的特定关键字参数（在``dict``中）。默认的``**kwargs``参数将在此之上应用。

          - ``limitprice``（默认值：``None``）

            *高端*停止订单的特定价格

          - ``stopexec``（默认值：``bt.Order.Limit``）

            *高端*订单的特定执行类型

          - ``limitargs``（默认值：``{}``）

            传递给高端订单的特定关键字参数（在``dict``中）。默认的``**kwargs``参数将在此之上应用。

        可以使用以下方法抑制高/低端订单：

          - ``limitexec=None``抑制*高端*

          - ``stopexec=None``抑制*低端*

        返回：

          - 包含3个订单[order，stop side，limit side]的列表

          - 如果已抑制高/低端订单，则返回值仍将包含3个订单，但被抑制的订单将具有值``None``
        '''


    def sell_bracket(self, data=None,
                     size=None, price=None, plimit=None,
                     exectype=bt.Order.Limit, valid=None, tradeid=0,
                     trailamount=None, trailpercent=None,
                     oargs={},
                     stopprice=None, stopexec=bt.Order.Stop, stopargs={},
                     limitprice=None, limitexec=bt.Order.Limit, limitargs={},
                     **kwargs):
        '''
        创建一个bracket订单组（低端-买单-高端）。默认行为如下：

          - 发出一个**sell**订单，执行为“Limit”

          - 发出一个*高端*bracket **buy**订单，执行为“Stop”

          - 发出一个*低端*bracket **buy**订单，执行为“Limit”。

        有关参数含义，请参见``bracket_buy``

         可以使用以下方法抑制高/低端订单：

          - ``stopexec=None``抑制*高端*

          - ``limitexec=None``抑制*低端*

        返回：

           - 包含3个订单[order，stop side，limit side]的列表

           - 如果已抑制高/低端订单，则返回值仍将包含3个订单，但被抑制的订单将具有值``None``
        '''



    def order_target_size(self, data=None, target=0, **kwargs):
        '''
        将仓位调整为目标大小的订单
        当前的仓位大小被考虑为实现目标的起点
        如果目标 > pos.size -> 买入 "target - pos.size"
        如果目标 < pos.size -> 卖出 "pos.size - target"
        返回值：
          - 生成的订单
           或者
          - 如果没有下达订单，则为“None”（“target == position.size”）

        '''


    def order_target_value(self, data=None, target=0.0, price=None, **kwargs):
        '''
        下达一个订单，将仓位调整为目标价值“target”

        当前的“value”被考虑为实现目标的起点

          - 如果没有“target”，则在数据上关闭仓位
          - 如果“target” > “value”，则在数据上买入
          - 如果“target” < “value”，则在数据上卖出

        返回值：

          - 生成的订单

          或者

          - 如果没有下达订单，则为“None”
        '''

    def order_target_percent(self, data=None, target=0.0, **kwargs):
        '''
        下达一个订单，将仓位调整为当前投资组合“value”的“target”百分比

        “target”以小数表示：“0.05”->“5%”

        它使用“order_target_value”来执行订单。

        示例：
          - “target=0.05”，投资组合价值为“100”

          - 要达到的“value”为“0.05 * 100 = 5”

          - “5”作为“target”值传递给“order_target_value”

        当前的“value”被考虑为实现目标的起点

        “position.size”用于确定仓位是“long”/“short”

          - 如果“target” > “value”
            - 如果“pos.size >= 0”（增加多头仓位），则买入
            - 如果“pos.size < 0”（增加空头仓位），则卖出

          - 如果“target” < “value”
            - 如果“pos.size >= 0”（减少多头仓位），则卖出
            - 如果“pos.size < 0”（减少空头仓位），则买入

        返回值：

          - 生成的订单

          或者

          - 如果没有下达订单，则为“None”（“target == position.size”）
        '''

    def getposition(self, data=None, broker=None):
        '''
        返回给定数据在给定经纪人中的当前持仓。

        如果两者都为None，则将使用主数据和默认经纪人

        还有一个属性“position”可用
        '''


    def getpositionbyname(self, name=None, broker=None):
        '''
        返回给定经纪人中给定名称的当前持仓。

        如果两者都为None，则将使用主数据和默认经纪人

        还有一个属性“positionbyname”可用
        '''


    def getpositions(self, broker=None):
        '''
        直接从经纪人返回当前数据的仓位

        如果给定的“broker”为None，则将使用默认经纪人

        还有一个属性“positions”可用
        '''


    def getpositionsbyname(self, broker=None):
        '''
        直接从经纪人返回当前名称的仓位

        如果给定的“broker”为None，则将使用默认经纪人

        还有一个属性“positionsbyname”可用
        '''

    def setsizer(self, sizer):
        '''
        替换默认（固定赌注）赌注器
        '''


    def getsizer(self):
        '''
        如果使用自动统计赌注，则返回正在使用的赌注器

        也可以使用“sizer”作为属性
        '''

    def getsizing(self, data=None, isbuy=True):
        '''
        返回赌注器实例为当前情况计算的赌注
        '''



class SignalStrategy(with_metaclass(MetaSigStrategy, Strategy)):
    '''这个“Strategy”的子类旨在使用**信号**进行自动操作。

    *信号*通常是指标和预期输出值：

      - ``> 0`` 是“多头”指示

      - ``< 0`` 是“空头”指示

    有5种类型的*信号*，分为2组。

    **主要组**：

      - ``LONGSHORT``：此信号的“多头”和“空头”指示都被采纳

      - ``LONG``：
        - 采纳“多头”指示以进行多头操作
        - 采纳“空头”指示以*关闭*多头仓位。但是：

          - 如果系统中有“LONGEXIT”信号（见下文），则将使用它来退出多头

          - 如果有“SHORT”信号可用且没有“LONGEXIT”可用，则将使用它来在开仓“空头”之前关闭“多头”

      - ``SHORT``：
        - 采纳“空头”指示以进行空头操作
        - 采纳“多头”指示以*关闭*空头仓位。但是：

          - 如果系统中有“SHORTEXIT”信号（见下文），则将使用它来退出空头

          - 如果有“LONG”信号可用且没有“SHORTEXIT”可用，则将使用它来在开仓“多头”之前关闭“空头”

    **退出组**：

      这2个信号旨在覆盖其他信号，并提供退出“多头”/“空头”仓位的标准

      - ``LONGEXIT``：采纳“空头”指示以退出“多头”仓位

      - ``SHORTEXIT``：采纳“多头”指示以退出“空头”仓位

    **订单发出**

      订单执行类型为“市场”，有效性为“无”（*Good until Canceled*）

    参数：

      - ``signals``（默认值：``[]``）：允许实例化信号并将其分配到正确类型的列表/元组

        预计通过``cerebro.add_signal``管理此参数

      - ``_accumulate``（默认值：``False``）：即使已经在市场上（多头/空头），也允许进入市场

      - ``_concurrent``（默认值：``False``）：即使已经有订单正在等待执行，也允许发出订单

      - ``_data``（默认值：``None``）：如果系统中存在多个数据，则是订单的目标。这可以是

        - ``None``：将使用系统中的第一个数据

        - 一个``int``：表示插入在该位置的数据

        - 一个``str``：在创建数据时（参数“name”）或在使用“cerebro.adddata（...，name =）”将其添加到cerebro时给出的名称

        - 一个``data``实例

    '''

